﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Collections;
using System.IO;

using JtextEpicsInterface;
using NationalInstruments.DAQmx;

// This is a driver for NI USB6008 in order to use it in the JtextEpics.
namespace JE_NI_driver
{
    public class JEdriver_NI6008 : IJEDriver
    {
        private const string DName = "JED_NI6008";
        private Task AITask;
        // SampleMode is used to specifie if a task acquires or generates a finite number of samples or if it continuously acquires or generates samples.
        private SampleQuantityMode SampleMode;
        // the number of samples to acquire or generate for each channel if SampleQuantityMode is FiniteSamples. If SampleQuantityMode is ContinuousSamples, NI-DAQmx uses this value to determine the buffer size.
        private int SamplesPerChannel;
        // Specifie if AI channels exist
        private bool AI;
        private AnalogMultiChannelReader AIreader;
        // the order of AI channels
        private Hashtable AIOrder;
        // the buffer of continuous AI channels
        private double[] CAIArray;
        // the buffer of finite AI channels
        private double[,] FAIArray;
        // AO is not used for the moment
        /*
        private Task AOTask;
        private bool AO;
        private AnalogSingleChannelWriter AOwriter;
        */
        private Task DITask;
        private bool DI;
        private DigitalSingleChannelReader DIReader;
        private bool[] DIArray;

        private Task DOTask;
        private bool DO;
        private DigitalSingleChannelWriter DOwriter;
        private bool[] DOArray;

        // the buffer of all channels
        private Hashtable ChannelList;

        #region IJEDriver Members
        // Get the name of the driver,read only
        public string DriverName
        {
            get
            {
                return DName;
            }
        }

        /// <summary>
        /// some initialization work
        /// </summary>
        public JEdriver_NI6008()
        {
            AI = false;
            // AO is not used for the moment
            //AO = false;
            DI = false;
            DO = false;
            AIOrder = new Hashtable();
            ChannelList = new Hashtable();
        }

        /// <summary>
        /// Initialize the whole hardware,get the property from XML.channel information,timing parameters and start trigger parameters.
        /// </summary>
        /// <param name="DriverProp"></param>
        /// <returns></returns>
        public bool IniHard(Record_prop DriverProp)
        {
            string HardPropPath = AppDomain.CurrentDomain.BaseDirectory.ToString();
            XmlReader XmlReader = XmlReader.Create(HardPropPath + "HardProp.xml");
            string[] HardProp = new string[4];
            string[] ChannelProp = new string[4];
            XmlReader.Read();
            XmlReader.ReadStartElement("Config-Driver");
            XmlReader.ReadStartElement("HardProp");
            XmlReader.ReadStartElement("AIHardProp");
            HardProp[0] = XmlReader.ReadString();
            XmlReader.ReadEndElement();
            XmlReader.ReadStartElement("AOHardProp");
            HardProp[1] = XmlReader.ReadString();
            XmlReader.ReadEndElement();
            XmlReader.ReadStartElement("DIHardProp");
            HardProp[2] = XmlReader.ReadString();
            XmlReader.ReadEndElement();
            XmlReader.ReadStartElement("DOHardProp");
            HardProp[3] = XmlReader.ReadString();
            XmlReader.ReadEndElement();
            XmlReader.ReadEndElement();
            XmlReader.ReadStartElement("ChannelProp");
            XmlReader.ReadStartElement("AI");
            ChannelProp[0] = XmlReader.ReadString();
            XmlReader.ReadEndElement();
            XmlReader.ReadStartElement("AO");
            ChannelProp[1] = XmlReader.ReadString();
            XmlReader.ReadEndElement();
            XmlReader.ReadStartElement("DI");
            ChannelProp[2] = XmlReader.ReadString();
            XmlReader.ReadEndElement();
            XmlReader.ReadStartElement("DO");
            ChannelProp[3] = XmlReader.ReadString();
            XmlReader.Close();

            if (ChannelProp[0] != "Null")
            {
                AI = true;
                string[] AIVoltageP = ChannelProp[0].Trim().Split(new Char[] { ';' });
                if (AIVoltageP[0] != "AIVoltage")
                {
                    Console.WriteLine("AIVoltage Channel Information does not match,NI6008 Hard Initialize Error!");
                    return false;
                }
                AITerminalConfiguration AIterminal;
                switch (AIVoltageP[2])
                {
                    case "Differential":
                        AIterminal = AITerminalConfiguration.Differential;
                        break;
                    case "Nrse":
                        AIterminal = AITerminalConfiguration.Nrse;
                        break;
                    case "Pseudodifferential":
                        AIterminal = AITerminalConfiguration.Pseudodifferential;
                        break;
                    case "Rse":
                        AIterminal = AITerminalConfiguration.Rse;
                        break;
                    default:
                        Console.WriteLine("AIVoltage Channel Information does not match,NI6008 Hard Initialize Error!");
                        return false;
                }
                double min = double.Parse(AIVoltageP[3]);
                double max = double.Parse(AIVoltageP[4]);
                AIVoltageUnits units;
                switch (AIVoltageP[5])
                {
                    case "Volts":
                        units = AIVoltageUnits.Volts;
                        break;
                    case "FromCustomScale":
                        units = AIVoltageUnits.FromCustomScale;
                        break;
                    case "FromTeds":
                        units = AIVoltageUnits.FromTeds;
                        break;
                    case "-1":
                        units = (AIVoltageUnits)(-1);
                        break;
                    default:
                        Console.WriteLine("AIVoltage Channel Information does not match,NI6008 Hard Initialize Error!");
                        return false;
                }
                try
                {
                    // Create a new task
                    AITask = new Task("NI6008AI");
                    // Create a AIChannel reader
                    AIreader = new AnalogMultiChannelReader(AITask.Stream);
                    // Create a AI virtual channel
                    AITask.AIChannels.CreateVoltageChannel(AIVoltageP[1], "", AIterminal, min, max, units);
                    // Verify that all task parameters are valid for the hardware
                    AITask.Control(TaskAction.Verify);
                    Console.WriteLine("NI6008 AI Hard Initialized!");
                    Console.WriteLine("NI6008 Channel Initialized!");
                    Console.WriteLine(ChannelProp[0]);
                    Console.WriteLine(AITask.AIChannels.Count);
                    // add the channel into AIOrder
                    AIOrder.Add(AIVoltageP[1], AITask.AIChannels.Count-1);
                }
                catch (DaqException IniHardexp)
                {
                    Console.WriteLine("NI6008 AI Hard Initialize Error!");
                    Console.WriteLine(IniHardexp.Message);
                    LogRecord(IniHardexp.Message);
                    throw (IniHardexp);
                    return false;
                }

                // Obtain the timing parameters from HardProp
                int found1 = HardProp[0].IndexOf("TimingP:");
                int found2 = HardProp[0].IndexOf("TriggerP:");
                string temp = HardProp[0].Substring(found1, found2 - found1);
                string[] timingP = temp.Split(new Char[] { ';', ':' });
                if ((timingP[1] == "ContinuousSamples") || (timingP[1] == "FiniteSamples"))
                {             
                    switch (timingP[1])
                    {
                        case "ContinuousSamples":
                            SampleMode = SampleQuantityMode.ContinuousSamples;
                            AITask.Stream.ReadOverwriteMode = ReadOverwriteMode.OverwriteUnreadSamples;
                            AITask.Stream.ReadOffset = 0;
                            AITask.Stream.ReadRelativeTo = ReadRelativeTo.MostRecentSample;
                            break;
                        case "FiniteSamples":
                            SampleMode = SampleQuantityMode.FiniteSamples;
                            break;
                        /* Not used for the moment
                          case "HardwareTimedSinglePoint":
                              sampleMode = SampleQuantityMode.HardwareTimedSinglePoint;
                              break;
                        */
                        default:
                            Console.WriteLine("AIHardProp Information does not match,NI6008 Hard Initialize Error!");
                            return false;
                    }
                    double rate = double.Parse(timingP[3]);
                    SampleClockActiveEdge activeEdge;
                    switch (timingP[4])
                    {
                        case "Rising":
                            activeEdge = SampleClockActiveEdge.Rising;
                            break;
                        case "Falling":
                            activeEdge = SampleClockActiveEdge.Falling;
                            break;
                        default:
                            Console.WriteLine("AIHardProp Information does not match,NI6008 Hard Initialize Error!");
                            return false;
                    }
                    SamplesPerChannel = int.Parse(timingP[5]);
                    switch (SampleMode)
                    {
                        case SampleQuantityMode.ContinuousSamples:
                            // add the channel into ChannelList
                            ChannelList.Add(AIVoltageP[1], (double)0);
                            break;
                        case SampleQuantityMode.FiniteSamples:
                            ArrayList AIAL = new ArrayList();
                            for (int i = 0; i < SamplesPerChannel; i++)
                            {
                                AIAL.Add((double)0);
                            }
                            // add the channel into ChannelList
                            ChannelList.Add(AIVoltageP[1],(double[])AIAL.ToArray(typeof(double)));
                            break;
                    }
                    try
                    {
                        // Configure the timing parameters
                        AITask.Timing.ConfigureSampleClock(timingP[2], rate, activeEdge, SampleMode, SamplesPerChannel);
                        // Verify that all task parameters are valid for the hardware
                        AITask.Control(TaskAction.Verify);
                        Console.WriteLine("NI6008 AI Timing Configured!");
                        Console.WriteLine(temp);
                    }
                    catch (DaqException ConfTimingexp)
                    {
                        Console.WriteLine("NI6008 AI Timing Configure Error!");
                        Console.WriteLine(ConfTimingexp.Message);
                        LogRecord(ConfTimingexp.Message);
                        throw (ConfTimingexp);
                        return false;
                    }
                }
                else
                {
                    Console.WriteLine("AIHardProp Information does not match,NI6008 Hard Initialize Error!");
                    return false;
                }

                // Obtain the start trigger parameters from HardProp
                found1 = HardProp[0].IndexOf("TriggerP:");
                temp = HardProp[0].Substring(found1);
                string[] triggerP = temp.Split(new Char[] { ';', ':' });
                if (triggerP[1] != "Null")
                {
                    DigitalEdgeStartTriggerEdge edge;
                    switch (triggerP[2])
                    {
                        case "Rising":
                            edge = DigitalEdgeStartTriggerEdge.Rising;
                            break;
                        case "Falling":
                            edge = DigitalEdgeStartTriggerEdge.Falling;
                            break;
                        default:
                            Console.WriteLine("AIHardProp Information does not match,NI6008 Hard Initialize Error!");
                            return false;
                    }
                    try
                    {
                        // Configure the start trigger which occur on a digital edge
                        AITask.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger(triggerP[1], edge);
                        // Verify that all task parameters are valid for the hardware
                        AITask.Control(TaskAction.Verify);
                        Console.WriteLine("NI6008 AI Trigger Configured!");
                        Console.WriteLine(temp);
                    }
                    catch (DaqException ConfTriggerexp)
                    {
                        Console.WriteLine("NI6008 AI Trigger Configure Error!");
                        Console.WriteLine(ConfTriggerexp.Message);
                        LogRecord(ConfTriggerexp.Message);
                        throw (ConfTriggerexp);
                        return false;
                    }
                }
            }
            // AO is not used for the moment
            /*
            if (ChannelProp[1] != "Null")
            {
                AO = true;
                string[] AOVoltageP = ChannelProp[1].Trim().Split(new Char[] { ';' });
                if (AOVoltageP[0] != "AOVoltage")
                {
                    Console.WriteLine("AOVoltage Channel Information does not match,NI6008 Hard Initialize Error!");
                    return false;
                }
                double min = double.Parse(AOVoltageP[2]);
                double max = double.Parse(AOVoltageP[3]);
                AOVoltageUnits units;
                switch (AOVoltageP[4])
                {
                    case "Volts":
                        units = AOVoltageUnits.Volts;
                        break;
                    case "FromCustomScale":
                        units = AOVoltageUnits.FromCustomScale;
                        break;
                    default:
                        Console.WriteLine("AOVoltage Channel Information does not match,NI6008 Hard Initialize Error!");
                        return false;
                }
                try
                {
                    // Create a new task
                    AOTask = new Task("NI6008AO");
                    // Create a AOChannel writer
                    AOwriter = new AnalogSingleChannelWriter(AOTask.Stream);
                    // Create a AO virtual channel
                    AOTask.AOChannels.CreateVoltageChannel(AOVoltageP[1], "", min, max, units);
                    // Verify that all task parameters are valid for the hardware
                    AOTask.Control(TaskAction.Verify);
                    // add the channel into ChannelList
                    ChannelList.Add(AOVoltageP[1], "AO");
                    Console.WriteLine("NI6008 AO Hard Initialized!");
                    Console.WriteLine("NI6008 Channel Initialized!");
                    Console.WriteLine(ChannelProp[1]);
                    Console.WriteLine(AOTask.AOChannels.Count);
                }
                catch (DaqException IniHardexp)
                {
                    Console.WriteLine("NI6008 AO Hard Initialize Error!");
                    Console.WriteLine(IniHardexp.Message);
                    return false;
                }
            }
            */
            if (ChannelProp[2] != "Null")
            {
                DI = true;
                string[] DIP = ChannelProp[2].Trim().Split(new Char[] { ';' });
                if (DIP[0] != "DI")
                {
                    Console.WriteLine("DI Channel Information does not match,NI6008 Hard Initialize Error!");
                    return false;
                }
                ArrayList DIAL = new ArrayList();
                for (int i = 0; i < int.Parse(DIP[1]); i++)
                {
                    DIAL.Add(false);
                }
                DIArray = (bool[])DIAL.ToArray(typeof(bool));
                ChannelLineGrouping grouping;
                switch (DIP[3])
                {
                    case "OneChannelForAllLines":
                        grouping = ChannelLineGrouping.OneChannelForAllLines;
                        break;
                    case "OneChannelForEachLine":
                        grouping = ChannelLineGrouping.OneChannelForEachLine;
                        break;
                    default:
                        Console.WriteLine("DI Channel Information does not match,NI6008 Hard Initialize Error!");
                        return false;
                }
                try
                {
                    // Create a new task
                    DITask = new Task("NI6008DI");
                    // Create a DIChannel reader
                    DIReader = new DigitalSingleChannelReader(DITask.Stream);
                    // Create a DI virtual channel
                    DITask.DIChannels.CreateChannel(DIP[2], "", grouping);
                    // Verify that all task parameters are valid for the hardware
                    DITask.Control(TaskAction.Verify);
                    Console.WriteLine("NI6008 DI Hard Initialized!");
                    Console.WriteLine("NI6008 Channel Initialized!");
                    Console.WriteLine(ChannelProp[2]);
                    Console.WriteLine(DITask.DIChannels.Count);
                }
                catch (DaqException IniChannelexp)
                {
                    Console.WriteLine("NI6008 DI Hard Initialize Error!");
                    Console.WriteLine(IniChannelexp.Message);
                    LogRecord(IniChannelexp.Message);
                    throw (IniChannelexp);
                    return false;
                }

                // Obtain the timing parameters from HardProp
                int found1 = HardProp[2].IndexOf("TimingP:");
                int found2 = HardProp[2].IndexOf("TriggerP:");
                string temp = HardProp[2].Substring(found1, found2 - found1);
                string[] timingP = temp.Split(new Char[] { ';', ':' });
                if ((timingP[1] == "ContinuousSamples")||(timingP[1]=="FiniteSamples"))
                {
                    switch (timingP[1])
                    {
                        case "ContinuousSamples":
                            SampleMode = SampleQuantityMode.ContinuousSamples;
                            break;
                        case "FiniteSamples":
                            SampleMode = SampleQuantityMode.FiniteSamples;
                            break;
                        /* Not used for the moment
                          case "HardwareTimedSinglePoint":
                              sampleMode = SampleQuantityMode.HardwareTimedSinglePoint;
                              break;
                        */
                        default:
                            Console.WriteLine("DIHardProp Information does not match,NI6008 Hard Initialize Error!");
                            return false;
                    }
                    double rate = double.Parse(timingP[3]);
                    SampleClockActiveEdge activeEdge;
                    switch (timingP[4])
                    {
                        case "Rising":
                            activeEdge = SampleClockActiveEdge.Rising;
                            break;
                        case "Falling":
                            activeEdge = SampleClockActiveEdge.Falling;
                            break;
                        default:
                            Console.WriteLine("DIHardProp Information does not match,NI6008 Hard Initialize Error!");
                            return false;
                    }
                    SamplesPerChannel = int.Parse(timingP[5]);
                    try
                    {
                        // Configure the timing parameters
                        DITask.Timing.ConfigureSampleClock(timingP[2], rate, activeEdge, SampleMode, SamplesPerChannel);
                        // Verify that all task parameters are valid for the hardware
                        DITask.Control(TaskAction.Verify);
                        Console.WriteLine("NI6008 DI Timing Configured!");
                        Console.WriteLine(temp);
                    }
                    catch (DaqException ConfTimingexp)
                    {
                        Console.WriteLine("NI6008 DI Timing Configure Error!");
                        Console.WriteLine(ConfTimingexp.Message);
                        LogRecord(ConfTimingexp.Message);
                        throw (ConfTimingexp);
                        return false;
                    }
                }
                else if (timingP[1] == "OnDemand")
                {
                    try
                    {
                        // Configure the timing parameters
                        DITask.Timing.SampleTimingType = SampleTimingType.OnDemand;
                        // Verify that all task parameters are valid for the hardware
                        DITask.Control(TaskAction.Verify);
                        Console.WriteLine("NI6008 DI Timing Configured!");
                        Console.WriteLine(temp);
                    }
                    catch (DaqException ConfTimingexp)
                    {
                        Console.WriteLine("NI6008 DI Timing Configure Error!");
                        Console.WriteLine(ConfTimingexp.Message);
                        LogRecord(ConfTimingexp.Message);
                        throw (ConfTimingexp);
                        return false;
                    }
                }
                else
                {
                    Console.WriteLine("DIHardProp Information does not match,NI6008 Hard Initialize Error!");
                    return false;
                }

                // Obtain the start trigger parameters from HardProp
                found1 = HardProp[2].IndexOf("TriggerP:");
                temp = HardProp[2].Substring(found1);
                string[] triggerP = temp.Split(new Char[] { ';', ':' });
                if (triggerP[1] != "Null")
                {
                    DigitalEdgeStartTriggerEdge edge;
                    switch (triggerP[2])
                    {
                        case "Rising":
                            edge = DigitalEdgeStartTriggerEdge.Rising;
                            break;
                        case "Falling":
                            edge = DigitalEdgeStartTriggerEdge.Falling;
                            break;
                        default:
                            Console.WriteLine("DIHardProp Information does not match,NI6008 Hard Initialize Error!");
                            return false;
                    }
                    try
                    {
                        // Configure the start trigger which occur on a digital edge
                        DITask.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger(triggerP[1], edge);
                        // Verify that all task parameters are valid for the hardware
                        DITask.Control(TaskAction.Verify);
                        Console.WriteLine("NI6008 DI Trigger Configured!");
                        Console.WriteLine(temp);
                    }
                    catch (DaqException ConfTriggerexp)
                    {
                        Console.WriteLine("NI6008 DI Trigger Configure Error!");
                        Console.WriteLine(ConfTriggerexp.Message);
                        LogRecord(ConfTriggerexp.Message);
                        throw (ConfTriggerexp);
                        return false;
                    }
                }
            }
            if (ChannelProp[3] != "Null")
            {
                DO = true;
                string[] DOP = ChannelProp[3].Trim().Split(new Char[] { ';' });
                if (DOP[0] != "DO")
                {
                    Console.WriteLine("DO Channel Information does not match,NI6008 Hard Initialize Error!");
                    return false;
                }
                ArrayList DOAL = new ArrayList();
                for (int i = 0; i < int.Parse(DOP[1]); i++)
                {
                    DOAL.Add(false);
                }
                DOArray = (bool[])DOAL.ToArray(typeof(bool));
                ChannelLineGrouping grouping;
                switch (DOP[3])
                {
                    case "OneChannelForAllLines":
                        grouping = ChannelLineGrouping.OneChannelForAllLines;
                        break;
                    case "OneChannelForEachLine":
                        grouping = ChannelLineGrouping.OneChannelForEachLine;
                        break;
                    default:
                        Console.WriteLine("DO Channel Information does not match,NI6008 Hard Initialize Error!");
                        return false;
                }
                try
                {
                    // Create a new task
                    DOTask = new Task("NI6008DO");
                    // Create a DOChannel writer
                    DOwriter = new DigitalSingleChannelWriter(DOTask.Stream);
                    // Create a DO virtual channel
                    DOTask.DOChannels.CreateChannel(DOP[2], "", grouping);
                    // Verify that all task parameters are valid for the hardware
                    DOTask.Control(TaskAction.Verify);
                    Console.WriteLine("NI6008 DO Hard Initialized!");
                    Console.WriteLine("NI6008 Channel Initialized!");
                    Console.WriteLine(ChannelProp[3]);
                    Console.WriteLine(DOTask.DOChannels.Count);
                }
                catch (DaqException IniChannelexp)
                {
                    Console.WriteLine("NI6008 Hard Initialize Error!");
                    Console.WriteLine(IniChannelexp.Message);
                    LogRecord(IniChannelexp.Message);
                    throw (IniChannelexp);
                    return false;
                }

                // Obtain the timing parameters from HardProp
                int found1 = HardProp[3].IndexOf("TimingP:");
                int found2 = HardProp[3].IndexOf("TriggerP:");
                string temp = HardProp[3].Substring(found1, found2 - found1);
                string[] timingP = temp.Split(new Char[] { ';', ':' });
                if (timingP[1] == "OnDemand")
                {
                    try
                    {
                        // Configure the timing parameters
                        DOTask.Timing.SampleTimingType = SampleTimingType.OnDemand;
                        // Verify that all task parameters are valid for the hardware
                        DOTask.Control(TaskAction.Verify);
                        Console.WriteLine("NI6008 DO Timing Configured!");
                        Console.WriteLine(temp);
                    }
                    catch (DaqException ConfTimingexp)
                    {
                        Console.WriteLine("NI6008 DO Timing Configure Error!");
                        Console.WriteLine(ConfTimingexp.Message);
                        LogRecord(ConfTimingexp.Message);
                        throw (ConfTimingexp);
                        return false;
                    }
                }
                else
                {
                    Console.WriteLine("DOHardProp Information does not match,NI6008 Hard Initialize Error!");
                    return false;
                }
            }
            Console.WriteLine("NI6008 Hard Initialized!");
            return true;
        }

        /// <summary>
        /// Dispose all the task
        /// </summary>
        /// <param name="DesRecord"></param>
        public void KillHard(Record_prop DesRecord)
        {
            try
            {
                // Clear the task
                if (AI)
                {
                    AITask.Dispose();
                }
                // AO is not used for the moment
                /*
                if (AO)
                {
                    AOTask.Dispose();
                }
                */
                if (DI)
                {
                    DITask.Dispose();
                }
                if (DO)
                {
                    DOTask.Dispose();
                }
            }
            catch (DaqException killHardexp)
            {
                Console.WriteLine(killHardexp.Message);
                LogRecord(killHardexp.Message);
                throw (killHardexp);
            }
        }

        /// <summary>
        /// Initialize the channels,get the property from Record_prop.
        /// </summary>
        /// <param name="DriverProp"></param>
        /// <returns></returns>
        public bool IniChannel(Record_prop DriverProp)
        {
            // Obtain the channel parameters to create a virtual channel from DriverProp.Drv_path,which is a string
            string[] channelP = DriverProp.Drv_path.Trim().Split(new Char[] { ';' });
            if (ChannelList.ContainsKey(channelP[1]) == false)
            {
                switch (channelP[0])
                {
                    case "AIVoltage":
                        if (AI)
                        {
                            AITerminalConfiguration AIterminal;
                            switch (channelP[2])
                            {
                                case "Differential":
                                    AIterminal = AITerminalConfiguration.Differential;
                                    break;
                                case "Nrse":
                                    AIterminal = AITerminalConfiguration.Nrse;
                                    break;
                                case "Pseudodifferential":
                                    AIterminal = AITerminalConfiguration.Pseudodifferential;
                                    break;
                                case "Rse":
                                    AIterminal = AITerminalConfiguration.Rse;
                                    break;
                                default:
                                    Console.WriteLine("AIHardProp Information does not match,NI6008 Hard Initialize Error!");
                                    return false;
                            }
                            double min = double.Parse(channelP[3]);
                            double max = double.Parse(channelP[4]);
                            AIVoltageUnits units;
                            switch (channelP[5])
                            {
                                case "Volts":
                                    units = AIVoltageUnits.Volts;
                                    break;
                                case "FromCustomScale":
                                    units = AIVoltageUnits.FromCustomScale;
                                    break;
                                case "FromTeds":
                                    units = AIVoltageUnits.FromTeds;
                                    break;
                                case "-1":
                                    units = (AIVoltageUnits)(-1);
                                    break;
                                default:
                                    Console.WriteLine("AIHardProp Information does not match,NI6008 Hard Initialize Error!");
                                    return false;
                            }
                            try
                            {
                                // Create a AIVoltage virtual channel
                                AITask.AIChannels.CreateVoltageChannel(channelP[1], "", AIterminal, min, max, units);
                                // Verify that all task parameters are valid for the hardware
                                AITask.Control(TaskAction.Verify);
                                Console.WriteLine("NI6008 Channel Initialized!");
                                Console.WriteLine(DriverProp.Drv_path.Trim());
                                Console.WriteLine(AITask.AIChannels.Count);
                                // add the channel into AIOrder
                                AIOrder.Add(channelP[1], AITask.AIChannels.Count-1);
                                switch (SampleMode)
                                {
                                    case SampleQuantityMode.ContinuousSamples:
                                        // add the channel into ChannelList
                                        ChannelList.Add(channelP[1], (double)0);
                                        break;
                                    case SampleQuantityMode.FiniteSamples:
                                        ArrayList AIAL = new ArrayList();
                                        for (int i = 0; i < SamplesPerChannel; i++)
                                        {
                                            AIAL.Add((double)0);
                                        }
                                        // add the channel into ChannelList
                                        ChannelList.Add(channelP[1], (double[])AIAL.ToArray(typeof(double)));
                                        break;
                                }
                                return true;
                            }
                            catch (DaqException IniChannelexp)
                            {
                                Console.WriteLine("NI6008 Channel Initialize Error!");
                                Console.WriteLine(IniChannelexp.Message);
                                LogRecord(IniChannelexp.Message);
                                throw (IniChannelexp);
                                return false;
                            }
                        }
                        else
                        {
                            Console.WriteLine("NI6008 Channel Initialize Error, AI Hard not Initialized!");
                            return false;
                        }
                    // AO is not used for the moment
                    /*
                    case "AOVoltage":
                        if (AO)
                        {
                            double min = double.Parse(channelP[2]);
                            double max = double.Parse(channelP[3]);
                            AOVoltageUnits units;
                            switch (channelP[4])
                            {
                                case "Volts":
                                    units = AOVoltageUnits.Volts;
                                    break;
                                case "FromCustomScale":
                                    units = AOVoltageUnits.FromCustomScale;
                                    break;
                                default:
                                    Console.WriteLine("AOHardProp Information does not match,NI6008 Hard Initialize Error!");
                                    return false;
                            }
                            try
                            {
                                // Create a AOVoltage virtual channel
                                AOTask.AOChannels.CreateVoltageChannel(channelP[1], "", min, max, units);
                                // Verify that all task parameters are valid for the hardware
                                AOTask.Control(TaskAction.Verify);
                                // add the channel into ChannelList
                                ChannelList.Add(channelP[1], "AO");
                                Console.WriteLine("NI6008 Channel Initialized!");
                                Console.WriteLine(DriverProp.Drv_path.Trim());
                                Console.WriteLine(AOTask.AOChannels.Count);
                                return true;
                            }
                            catch (DaqException IniChannelexp)
                            {
                                Console.WriteLine("NI6008 Channel Initialize Error!");
                                Console.WriteLine(IniChannelexp.Message);
                                return false;
                            }
                        }
                        else
                        {
                            Console.WriteLine("NI6008 Channel Initialize Error, AO Hard not Initialized!");
                            return false;
                        }
                    */
                    case "DI":
                        if (DI)
                        {
                            // add the channel into ChannelList
                            ChannelList.Add(channelP[1], false);
                            Console.WriteLine("NI6008 Channel Initialized!");
                            Console.WriteLine(DriverProp.Drv_path.Trim());
                            return true;
                        }
                        else
                        {
                            Console.WriteLine("NI6008 Channel Initialize Error, DI Hard not Initialized!");
                            return false;
                        }
                    case "DO":
                        if (DO)
                        {
                            // add the channel into ChannelList
                            ChannelList.Add(channelP[1], false);
                            Console.WriteLine("NI6008 Channel Initialized!");
                            Console.WriteLine(DriverProp.Drv_path.Trim());
                            return true;
                        }
                        else
                        {
                            Console.WriteLine("NI6008 Channel Initialize Error, DO Hard not Initialized!");
                            return false;
                        }
                    default:
                        Console.WriteLine("There is no Channel Type Information,NI6008 Channel Initialize Error!");
                        return false;
                }
            }
            else
            {
                Console.WriteLine("This Channel has been Initialized before!");
                return true;
            }
        }

        // KillChannel is not used
        public void KillChannel(Record_prop DesRecord)
        {
            throw new NotImplementedException();
        }

        int getErrorNum = 0;
        /// <summary>
        /// Get the value from the hardware,AI and DI
        /// </summary>
        /// <param name="DesRecord"></param>
        /// <returns></returns>
        public object GetVal(Record_prop DesRecord)
        {
            object data;
            string[] channelP = DesRecord.Drv_path.Trim().Split(new Char[] { ';' });
            switch (channelP[0])
            {
                case "AIVoltage":
                    try
                    {
                        switch (SampleMode)
                        {
                            case SampleQuantityMode.ContinuousSamples:
                                CAIArray = AIreader.ReadSingleSample();
                                ChannelList[channelP[1]] = CAIArray[(int)AIOrder[channelP[1]]];
                                data = Convert.ToDouble(ChannelList[channelP[1]]);
                                getErrorNum = 0;
                                break;
                            default:
                                double[] temp = (double[])ChannelList[channelP[1]];
                                for (int i = 0; i < SamplesPerChannel; i++)
                                {
                                    temp[i] = FAIArray[(int)AIOrder[channelP[1]], i];
                                }
                                ChannelList[channelP[1]] = (double[])temp;
                                data = (double[])temp;
                                break;
                        }
                        Console.WriteLine("\n" + channelP[1] + "    Read Operation!\n" + data);
                        getErrorNum = 0;
                    }
                    catch (DaqException Readexp)
                    {
                        Console.WriteLine("\n" + channelP[1] + "    Read Operation Error!");
                        Console.WriteLine(Readexp.Message);
                        switch (SampleMode)
                        {
                            case SampleQuantityMode.ContinuousSamples:
                                data = Convert.ToDouble(ChannelList[channelP[1]]);
                                break;
                            default:
                                data = (double[])ChannelList[channelP[1]];
                                break;
                        }
                        getErrorNum++;
                        if (getErrorNum > 10)
                        {
                            LogRecord(Readexp.Message);
                            throw (Readexp);
                        }
                    }
                    break;
                case "DI":
                    int line;
                    line = int.Parse(channelP[1]);
                    try
                    {
                        DIArray = DIReader.ReadSingleSampleMultiLine();
                        ChannelList[channelP[1]] = DIArray[line];
                        data = Convert.ToInt32(ChannelList[channelP[1]]);
                        Console.WriteLine("\nLine" + line + "   Read Operation!\n" + DIArray[line]);
                        getErrorNum = 0;
                    }
                    catch (DaqException Readexp)
                    {
                        Console.WriteLine("\nLine" + line + "   Read Operation Error!");
                        Console.WriteLine(Readexp.Message);
                        data = Convert.ToInt32(ChannelList[channelP[1]]);
                        getErrorNum++;
                        if (getErrorNum > 10)
                        {
                            LogRecord(Readexp.Message);
                            throw (Readexp);
                        }
                    }
                    break;
                default:
                    Console.WriteLine("There is no Channel Type Information,Read Operation Error!");
                    return false;
            }
            return data;
        }

        int setErrorNum = 0;
        /// <summary>
        /// Set the value to the hardware,AO and DO
        /// </summary>
        /// <param name="DesRecord"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public object SetVal(Record_prop DesRecord, object value)
        {
            string[] channelP = DesRecord.Drv_path.Trim().Split(new Char[] { ';' });
            switch (channelP[0])
            {
                case "AO":
                    return false;
                case "DO":
                    int line;
                    try
                    {
                        line = int.Parse(channelP[1]);
                        DOArray[line] = Convert.ToBoolean((int)value);
                        DOwriter.WriteSingleSampleMultiLine(true, DOArray);
                        Console.WriteLine("\nLine" + line + "   Write Operation!\n" + DOArray[line]);
                        setErrorNum = 0;
                        return true;
                    }
                    catch (DaqException Writeexp)
                    {
                        line = int.Parse(channelP[1]);
                        Console.WriteLine("\nLine" + line + "   Write Operation Error!\n");
                        Console.WriteLine(Writeexp.Message);
                        setErrorNum++;
                        if (setErrorNum > 10)
                        {
                            LogRecord(Writeexp.Message);
                            throw (Writeexp);
                        }
                        return false;
                    }
                default:
                    Console.WriteLine("There is no Channel Type Information,Read Operation Error!");
                    return false;
            }
        }

        /// <summary>
        /// Occurs when [on flush]
        /// </summary>
        public event FlushRecordHandler OnFlush;

        /// <summary>
        /// Start the driver
        /// </summary>
        /// <param name="DesRecord"></param>
        /// <returns></returns>
        public bool StartDriver(Record_prop DesRecord)
        {
            try
            {
                if (AI)
                {
                    AITask.Start();
                    if (SampleMode == SampleQuantityMode.FiniteSamples)
                    {
                        AITask.Stream.Timeout = 3000;
                        FAIArray = AIreader.ReadMultiSample(SamplesPerChannel);
                        Console.WriteLine("Read Finishied!");
                    }
                }
                // AO is not used for the moment
                /*
                if (AO)
                {
                    AOTask.Start();
                }
                */
                if (DI)
                {
                    DITask.Start();
                }
                if (DO)
                {
                    DOTask.Start();
                }
                Console.WriteLine("NI6008 Started!");
                return true;
            }
            catch (DaqException Startexp)
            {
                Console.WriteLine("NI6008 Start Error!");
                Console.WriteLine(Startexp.Message);
                LogRecord(Startexp.Message);
                throw (Startexp);
                return false;
            }
        }
        #endregion

        private void LogRecord(string Error)
        {
            Console.WriteLine("Start Error Record!");
            StreamWriter w = File.AppendText("NI6008_Log.txt");
            w.Write("\r\nlog : ");
            w.WriteLine("{1} {0}", DateTime.Now.ToLongTimeString(), DateTime.Now.ToLongDateString());
            w.WriteLine("  {0}", Error);
            w.Write("--------------------------------------------------");
            w.Close();
            Console.WriteLine("Error Record Finish!");
            return;
        }
    }
}